
#include <BText>
#include <BOpenGL>
#include <BRender>
#include "member_BText.h"
#include "member_BFont.h"
#include "member_BImage.h"
#include "member_BShape.h"

using namespace BWE;

#define member					(*(member_BText*)_ptr)
#define member_allocate()		_ptr = new member_BText(this)
#define member_release()		delete (member_BText*)_ptr

BText::BText()
{
	member_allocate();
}
BText::~BText()
{
	member_release();
}

void BText::setAlign(Align align)
{
	if (member.align != align)
	{
		member.align = align;
		this->dirty();
	}
}
Align BText::align() const
{
	return member.align;
}

void BText::setQuad(const BQuad& quad)
{
	if (member.quad != quad)
	{
		member.quad = quad;
		this->dirty();
	}
}
const BQuad& BText::quad() const
{
	return member.quad;
}

void BText::setText(const BString& text)
{
	if(member.text != text)
	{
		member.text = text;
		this->dirty();
	}
}
const BString& BText::text() const
{
	return member.text;
}

void BText::setFont(const BString& family, int size)
{
	if (!member.font)
	{
		member.font = new BFont();
	}
	if (member.font->family() != family)
	{
		member.font->setFamily(family);
		member.font->setSize(size);
		this->dirty();
	}
}
void BText::setFont(BFont* font)
{
	if (member.font != font)
	{
		member.font = font;
		this->dirty();
	}
}
BFont* BText::font()
{
	return member.font.ptr();
}
const BFont* BText::font() const
{
	return member.font.ptr();
}

void BText::setFontSize(float fontSize)
{
	if (member.fontSize != fontSize)
	{
		member.fontSize = fontSize;
		this->dirty();
	}
}
float BText::fontSize() const
{
	return member.fontSize;
}

void BText::setTextColor(BColorArray* textColor)
{
	member.textColor = textColor;
}
const BColorArray* BText::textColor() const
{
	return member.textColor;
}
BColorArray* BText::textColor()
{
	return member.textColor;
}

BBox BText::refresh()
{
	if (member.font && member.text.size())
	{
		member.items.resize(member.text.count());
		BQuad quad = member.quad;
		if (quad == BQuad())
		{
			quad.a() = BVector(0, 0, 0);
			quad.b() = BVector(0, -member.fontSize, 0);
			quad.c() = BVector(1.0f, -member.fontSize, 0);
			quad.d() = BVector(1.0f, 0, 0);
		}
		const BVector& a = quad.a();
		BVector right = quad.d() - quad.a();
		BVector down = quad.b() - quad.a();
		right.normalize();
		down.normalize();

		int index = 0;
		BVector point = a + down * member.fontSize * 0.8f;
		float width = 0.0f;
		float height = member.fontSize;
		float width_mult = member.fontSize / member.font->height();
		for (BString::const_iterator cit = member.text.begin(); cit != member.text.end(); cit++)
		{
			BCode code = cit.value();
			if (code == '\n')
			{
				height += member.fontSize;
				point = a + down * height;
			}

			BSize codeSize = member.font->codeSize(code);
			float cw = codeSize.width() * width_mult;
			float ch = codeSize.height() * width_mult;

			CodeItem& item = member.items[index++];
			item.quad.a() = point - down * ch;
			item.quad.b() = point;
			item.quad.c() = point + right * cw;
			item.quad.d() = point - down * ch + right * cw;
			item.image = 0;
			item.imageQuad = item.quad;

			CodeInfo* info = font_member(member.font)->getCodeInfo(code);
			if (info)
			{
				item.image = member.font->bitmap(code);
				float left = info->left * width_mult;
				float top = info->top * width_mult;

				float bw = item.image->width() * width_mult;
				float bh = item.image->height() * width_mult;

				item.imageQuad.a() = point + right * left;
				item.imageQuad.b() = point + right * left + down * bh;
				item.imageQuad.c() = item.imageQuad.b() + right * bw;
				item.imageQuad.d() = item.imageQuad.a() + right * bw;
				item.imageQuad -= down * top;
			}
			point += right * cw;
			float distance = BLine(quad.a(), quad.b()).distance(point);
			if (width < distance)
				width = distance;
		}
		BRectf rect(0.0f, 0.0f, (member.quad.d() - member.quad.a()).length(), (member.quad.b() - member.quad.a()).length());
		BPointf offset = rect.align(member.align, width, height).pos();
		BVector vec(offset.x(), -offset.y(), 0);
		index = 0;
		for (BString::const_iterator cit = member.text.begin(); cit != member.text.end(); cit++)
		{
			CodeItem& item = member.items[index++];
			item.quad += vec;
			item.imageQuad += vec;
		}
	}
	BSpace space(member.quad.a());
	space.expand(member.quad.b());
	space.expand(member.quad.c());
	space.expand(member.quad.d());
	return space;
}
void BText::render(BRender& render)
{
	render.setColor(255, 255, 255);
	render.drawQuad(member.quad);
	//for (int i = 0; i < member.items.size(); i++)
	//{
	//	CodeItem& item = member.items[i];
	//	render.setColor(0, 255, 0);
	//	render.drawQuad(item.quad);
	//	render.setColor(255, 255, 0);
	//	render.drawQuad(item.imageQuad);
	//}
	
	render.setColor(this->color());

	BColorArray* colors = member.textColor;
	if (colors && colors->size() != member.items.size())
		colors = 0;

	glEnable(GL_TEXTURE_2D);
	for (int i = 0; i < member.items.size(); i++)
	{
		CodeItem& item = member.items[i];
		if (item.image)
		{
			const BVector& a = item.imageQuad.a();
			const BVector& b = item.imageQuad.b();
			const BVector& c = item.imageQuad.c();
			const BVector& d = item.imageQuad.d();

			if (colors)
			{
				const BColor& c = (*colors)[i];
				glColor4ub(c.r(), c.g(), c.b(), c.a());
			}

			item.image->bind();
			glBegin(GL_QUADS);
				glTexCoord2f(0, 0);		glVertex3f(a.x(), a.y(), a.z());
				glTexCoord2f(0, 1);		glVertex3f(b.x(), b.y(), b.z());
				glTexCoord2f(1, 1);		glVertex3f(c.x(), c.y(), c.z());
				glTexCoord2f(1, 0);		glVertex3f(d.x(), d.y(), d.z());
			glEnd();
			item.image->unbind();
		}
	}
	glDisable(GL_TEXTURE_2D);
}
